package com.onpositive.knowledge.model.value.audits;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.knowledge.model.ICanResolveWikiRefs;
import com.onpositive.knowledge.model.IHasUniverse;
import com.onpositive.knowledge.model.IUniverse;
import com.onpositive.knowledge.model.values.ReplacementProposals;
import com.onpositive.knowledge.model.values.ValueTraverser;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.units.ParsedValue;

public class ReferenceResolvingAudit extends AuditSourceContainer  implements IValueAudit {

	private static final long serialVersionUID = -3674919092840757511L;

	public ReferenceResolvingAudit() {
		super();
	}

	public static final String ID = "references-resolving-audit";
	
	public static final int VALIDITY_BARRIER = 1000 ;	

	@Override
	public void perform(IProperty prop, Iterable<Object> objects, AbstractAuditResult auditResult ) {
		
		if( auditResult == null || !( auditResult instanceof ReplacementProposals ) )
			return ;
		
		ReplacementProposals rp = (ReplacementProposals) auditResult ;
		Map<String,Object> metaInfo = new HashMap<String, Object>() ;
		metaInfo.put("audit-result", rp) ;
		OwnTraverser traverser = new OwnTraverser();
		traverser.iterateObjects(prop, objects, metaInfo, 0);

		rp.setComment(ID) ;
	}

	@Override
	public AbstractAuditResult createAuditResult(IProperty prop)
	{
		if( !isAcceptable(prop))
			return null ;
		
		ReplacementProposals replacementProposals = new ReplacementProposals( prop );
		replacementProposals.setValidityBarrier( VALIDITY_BARRIER ) ;
		replacementProposals.setAuditId(ID) ;	
		return  replacementProposals ;
	}
	
	private boolean isAcceptable( IProperty prop) {
		
		Boolean isService = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_IS_SERVICE_PROPERTY, Boolean.class, null ) ;
		if( isService != null && isService )
			return false;
		
		Boolean isDepricated = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_DEPRICATED_LABEL, Boolean.class, null ) ;
		if( isDepricated != null && isDepricated )
			return false;
		
		Boolean isIdent = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_IS_IDENTIFICATOR, Boolean.class, null ) ;
		if( isIdent == null || !isIdent ){
			if( getResultSource() == null )
				return false ;
				
			AbstractAuditResult _gResult = getResultSource().getAuditResult() ;
			if( _gResult instanceof GeneralAuditResult )
			{			
				GeneralAuditResult generalResult = (GeneralAuditResult) _gResult ;
				AbstractAuditResult _res = generalResult.getResult( IdentAudit.ID ) ;
				if( _res != null )
					return false ;					
			}
			else
				return false ;
		}

		return true ;
	}

	@Override
	public Set<String> getRequiredAudits() {
		return null;
	}
	@Override
	public String getId() {
		return ID;
	}
	
	private class OwnTraverser extends ValueTraverser {
		
		private ICanResolveWikiRefs resolver;
		
		public void itereteObjectValues(IProperty prop, Object obj, Map<String, Object> metaInfo, int ind){

			this.resolver = getResolver(obj);
			if(this.resolver==null)
				return;
			
			super.itereteObjectValues(prop, obj, metaInfo, ind);
		}

		private ICanResolveWikiRefs getResolver(Object obj) {
			if(!(obj instanceof IHasUniverse))
				return null;
			
			IHasUniverse universeOwner = (IHasUniverse) obj;
			IUniverse universe = universeOwner.getUniverse();
			if(!(universe instanceof ICanResolveWikiRefs))
				return null;
			
			ICanResolveWikiRefs universe2 = (ICanResolveWikiRefs) universe;
			return universe2;
		}

		@Override
		protected void process(IProperty prop, Object val, Map<String, Object> metaInfo, int index)
		{
			if(!(val instanceof ParsedValue))
				return;		
			
			Object aRes = metaInfo.get("audit-result");
			if(aRes==null)
				return;
			
			if(!(aRes instanceof ReplacementProposals))
				return;
			
			ReplacementProposals rp = (ReplacementProposals) aRes;			
			ParsedValue pv = (ParsedValue) val;
			this.resolver.processRefs(prop, pv, rp);			
		}
		
		@Override
		protected Class<?>[] createTargetClasses() {
			return new Class<?>[]{ ParsedValue.class};
		}
		
		@Override
		protected Class<?>[] createNecessaryClasses() {
			return new Class<?>[]{ ParsedValue.class};
		}
	};  

}
